﻿//#define debug
//#define standalone
//#define outputTable
//#define outputFile

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace _22yards.IndependentModules
{
    class DuckWorthLewis
    {
        List<List<double>> table;

        int scoreTeam1 = 0; //parameter change these to test
        int wicketsGoneTeam1 = 0; //parameter
        double oversGoneTeam1 = 0; //parameter
        int scoreTeam2 = 0; //parameter
        int wicketsGoneTeam2 = 0; //parameter
        double oversGoneTeam2 = 0; //parameter

        int totalOversPerInnings = 0;
        int totalOversPerInningsTeam2 = 0;
        int totalBallsPerInnings = 0;
        int totalBallsPerInningsTeam2 = 0;

        int ballsLostTeam1 = 0; //need this passed in
        int ballsLostTeam2 = 0; //do i need this

        double startingResourcesTeam1 = 0;
        double startingResourcesTeam2 = 0;

        double revisedResourcesTeam1 = 0;
        double revisedResourcesTeam2 = 0;
        int revisedTarget = 0;
        /**
         * For matches involving ICC full member nations, or for matches between teams 
            that play frst class cricket, the value of g50 should be 245.
            For lower levels of the game:
            •  under 19 international matches
             •  under 15 international matches
             •  women’s international matches
             •  matches between associate ICC member nations 
             the value of g50 should be 200
         **/
        int g50 = 245;

        DuckWorthLewis() { }//constructor

        DuckWorthLewis(int scoreTeam1, int wicketsGoneTeam1, double oversGoneTeam1)
        {
            this.scoreTeam1 = scoreTeam1;
            this.wicketsGoneTeam1 = wicketsGoneTeam1;
            this.oversGoneTeam1 = oversGoneTeam1;
        }
        DuckWorthLewis(int scoreTeam1, int wicketsGoneTeam1, double oversGoneTeam1,
            int scoreTeam2, int wicketsGoneTeam2, double oversGoneTeam2)
        {
            this.scoreTeam1 = scoreTeam1;
            this.wicketsGoneTeam1 = wicketsGoneTeam1;
            this.oversGoneTeam1 = oversGoneTeam1;
            this.scoreTeam2 = scoreTeam2;
            this.wicketsGoneTeam2 = wicketsGoneTeam2;
            this.oversGoneTeam2 = oversGoneTeam2;
        }
        //only need this constructor?
        DuckWorthLewis(int scoreTeam1, int wicketsGoneTeam1, double oversGoneTeam1,
            int scoreTeam2, int wicketsGoneTeam2, double oversGoneTeam2,
            int totalOversPerInnings, int totalOversPerInningsTeam2,
            int ballsLostTeam1, int ballsLostTeam2,
            int g50)
        {
            this.scoreTeam1 = scoreTeam1;
            this.wicketsGoneTeam1 = wicketsGoneTeam1;
            this.oversGoneTeam1 = oversGoneTeam1;
            this.scoreTeam2 = scoreTeam2;
            this.wicketsGoneTeam2 = wicketsGoneTeam2;
            this.oversGoneTeam2 = oversGoneTeam2;
            this.totalOversPerInnings = totalOversPerInnings;
            this.totalOversPerInningsTeam2 = totalOversPerInningsTeam2;
            this.ballsLostTeam1 = ballsLostTeam1;
            this.ballsLostTeam2 = ballsLostTeam2;
            this.g50 = g50;
        }
#if standalone        
        static void Main(string[] args)
        {
            DuckWorthLewis d = new DuckWorthLewis(250,0,0,40,1,12,50,50,0,60,245);
            int target = 0;
           target =  d.calcNewTarget();


#if outputTable
                for (int j = 0; j < table.Count; j++) {
                    for (int k = 0; k < table[j].Count; k++)
                    {

                        Console.Out.Write(table[j][k] + " ");
                    }
                    Console.Out.Write('\n'); 
                }
                
                Console.Out.Write("table.Count: " + table.Count);
                //end debug 
#endif //outputTable
#if outputFile     
           table.Reverse();
                string outputFileName = "reversedDLTable.txt";
                // Delete the file if it exists.
                if (File.Exists(outputFileName))
                {
                    File.Delete(outputFileName);
                }

               
                StreamWriter outStream = File.CreateText(outputFileName);
                for (int j = 0; j < table.Count; j++)
                {
                    for (int k = 0; k < table[j].Count; k++)
                    {
                        if (k == table[j].Count - 1) {
                            outStream.Write(table[j][k].ToString("##0.0"));
                        } else {
                            outStream.Write(table[j][k].ToString("##0.0") + " ");
                        }
                        
                    }
                    if (!(j == table.Count - 1))
                    {
                        outStream.Write("\r\n");
                    }
                }
                outStream.Close();
#endif //outputFile

        }//main
#endif
        public int calcNewTarget()
        {
            table = loadTable("reversedDLTable.txt");

            /**
             5.1  Note the number of overs per innings decided at the start of the game, 
               n.
             * From the table note the resource percentage available to Team 1 at the 
               start of their innings. 
               (for	n	=	50	this	is	100%.)
            **/

            //totalOversPerInnings = 50;//use matchtype enum to find this?, 50 for testing
            totalBallsPerInnings = totalOversPerInnings * 6;

            startingResourcesTeam1 = table[totalBallsPerInnings][0];
#if debug
            Console.WriteLine("startingResourcesTeam1: " + startingResourcesTeam1);
#endif
            //For all suspensions and any premature termination of Team 1’s innings, 
            //  calculate the total resource percentage lost using the procedure described 
            // in section 3.
            double resourcesLost = calcResourceLost(oversGoneTeam1, wicketsGoneTeam1, totalBallsPerInnings, ballsLostTeam1);
#if debug 
            Console.WriteLine("ResourcesLost: " + resourcesLost);
#endif

            // Subtract this from the starting resource percentage (5.1) to 
            //     give r1, the resource which was available to Team 1 for their innings.

            revisedResourcesTeam1 = startingResourcesTeam1 - resourcesLost;
#if debug 
            Console.WriteLine("revisedResourcesTeam1: " + revisedResourcesTeam1);
#endif
            // Note Team 1’s total score, s.
            //is already passed in as parameter
            //need to have how many overs for team2s innings passed in
            //5.4 Note the number of overs allocated to Team 2 at the start of their innings 
            totalBallsPerInningsTeam2 = totalOversPerInningsTeam2 * 6;

            //from the table note the resource percentage for this number of overs 
            // remaining and 0 wicket lost. This is r2, the resource percentage available 
            // to Team 2.
            startingResourcesTeam2 = table[totalBallsPerInningsTeam2][0];
#if debug
            Console.WriteLine("startingResourcesTeam2: " + startingResourcesTeam2);
#endif
            double resourcesLostTeam2 = calcResourceLost(oversGoneTeam2, wicketsGoneTeam2, totalBallsPerInningsTeam2, ballsLostTeam2);
#if debug          
            Console.WriteLine("resourcesLostTeam2: " + resourcesLostTeam2);
#endif
            revisedResourcesTeam2 = startingResourcesTeam2 - resourcesLostTeam2;
#if debug           
            Console.WriteLine("revisedResourcesTeam2: " + revisedResourcesTeam2);
#endif
            // If r2 differs from r1, which will happen if Team 1’s innings was 
            //  interrupted and/or Team 2’s was delayed, a revised target must be set.
            // TODO need to handle interuptions during team2s innings
            //implement the actual calc of new target
            //code here check revisedResourcesTeam1 against startingResourcesTeam2 

            //Calculate this revised target, t, as described in 5.6 below.
            /**
             * 
             5.6  If r2 is less than r1, Team 2’s revised target is obtained by reducing Team 1
                   score S in the ratio of r2 to r1, ignoring any fgures after the decimal point
                   and adding one run
                i.e. t = (s	x	r2/r1) + 1 (rounded down to a whole number, if necessary).
                If r2 is equal to r1, no revision is needed and Team 2’s target is one more 
               run than Team 1’s score.
                 i.e. t = s + 1
                If r2 is greater than r1, calculate the amount of excess resources, 
                r2 – r1, and take this percentage of the average 50-over total, g50, to give
               the extra runs needed, ignoring any fgures after the decimal point.
                i.e. t = S + (r2	–	r1) x g50/100 + 1 (rounded down to a whole number,  
               if necessary)
             **/
            // 5.6  If r2 is less than r1, Team 2’s revised target is obtained by reducing Team 1
            //   score S in the ratio of r2 to r1, ignoring any fgures after the decimal point
            //    and adding one run
            // i.e. t = (s	x	r2/r1) + 1 (rounded down to a whole number, if necessary).
            if (revisedResourcesTeam2 < revisedResourcesTeam1)
            {
                //TODO test here, should i be casting to int??
#if debug               
                Console.WriteLine("revisedResourcesTeam2: " + revisedResourcesTeam2);
                Console.WriteLine("revisedResourcesTeam1: " + revisedResourcesTeam1);
#endif
                revisedTarget = (int)Math.Floor(scoreTeam1 * revisedResourcesTeam2 / revisedResourcesTeam1 + 1);
#if debug                
                Console.WriteLine("revisedTarget : team 2 res was less than team1 revised res : " + revisedTarget);
#endif
                return revisedTarget;
            }

            //If r2 is equal to r1, no revision is needed and Team 2’s target is one more 
            // run than Team 1’s score.
            //   i.e. t = s + 1
            if (revisedResourcesTeam1 == revisedResourcesTeam2)
            {
                //no need to calculate, will it ever reach here
                revisedTarget = scoreTeam1 + 1;
#if debug                 
                Console.WriteLine("revisedTarget : team 2 res was equal team1 revised res : " + revisedTarget);
#endif
                return revisedTarget;
            }
            // If r2 is greater than r1, calculate the amount of excess resources, 
            //  r2 – r1, and take this percentage of the average 50-over total, g50, to give
            // the extra runs needed, ignoring any fgures after the decimal point.
            //  i.e. t = S + (r2	–	r1) x g50/100 + 1 (rounded down to a whole number,  
            // if necessary)
            if (revisedResourcesTeam2 > revisedResourcesTeam1)
            {
                double excessResources = revisedResourcesTeam2 - revisedResourcesTeam1;
#if debug                
                Console.WriteLine("revisedResourcesTeam1 : " + revisedResourcesTeam1);
                Console.WriteLine("revisedResourcesTeam2 : " + revisedResourcesTeam2);
                Console.WriteLine("excessResources : " + excessResources);
#endif
                revisedTarget = (int)Math.Floor(scoreTeam1 + g50 * excessResources / 100 + 1);
#if debug               
                Console.WriteLine("revisedTarget: " + revisedTarget);
                Console.WriteLine("revisedTarget : team 2 res was greater than team1 revised res : " + revisedTarget);
#endif
                return revisedTarget;
            }
            return 0;
        }

        public double calcResourceLost(double oversGone, int wicketsGone, int totalBallsPerInnings, int ballsLost)
        {
            /** Section 3
            3.1     For the start of the suspension in play, from the table note the resource 
                    percentage that remained for the appropriate number of overs/balls left 
                    and wickets lost.
            **/
            double resourcesLeftAfterSuspension = 0;
            string[] splitBalls;
            splitBalls = oversGone.ToString("##0.0").Split('.');
#if debug            
            Console.WriteLine("splitBalls[0](overs): " + splitBalls[0] + " splitBalls[1](balls): " + splitBalls[1]);
#endif
            int ballsGone = (int.Parse(splitBalls[0]) * 6) + int.Parse(splitBalls[1]);
#if debug            
            Console.WriteLine("oversGone: " + oversGone + " ballsGone: " + ballsGone);
#endif
            int ballsLeftAtSuspension = totalBallsPerInnings - ballsGone;
            double resourcesLeftAtSuspension = table[ballsLeftAtSuspension][wicketsGone];
#if debug           
            //Console.WriteLine("resourcesLeftAtSuspension: " + resourcesLeftAtSuspension);
#endif
            /**
            3.2     For the resumption of play after the suspension, from the table note the 
                    resource percentage now remaining for the revised number of overs/balls 
                    left and for the same number of wickets lost.
          
           
            3.4     If a suspension in play causes the innings to be terminated, the  
                    resource percentage on resumption (3.2) is zero and the percentage lost 
                    is the resource percentage which was remaining when the suspension 
                    occurred (3.1).
             **/
            if (ballsLeftAtSuspension <= ballsLost)
            { //if true 3.4 applies
#if debug 
                Console.WriteLine("zero or less balls left, innings terminated, return resourcesLeftAtSuspension as the resources lost ");
#endif
                return resourcesLeftAtSuspension;
            }
            else
            {
                // 3.3     Subtract the resource percentage in 3.2 from that in 3.1 to give the resource
                //  percentage lost.


                //next 2 lines implements  3.2    
                int ballsLeftAfterSuspension = ballsLeftAtSuspension - ballsLost;
                //Console.WriteLine("ballsLeftAfterSuspension: " + ballsLeftAfterSuspension);
                resourcesLeftAfterSuspension = table[ballsLeftAfterSuspension][wicketsGone];

                //TODO TEST here
#if debug                
                Console.WriteLine("resourcesLeftAfterSuspension: " + resourcesLeftAfterSuspension);
#endif
            }
            /**
            
           
            
                    
            
            3.5     If more than one suspension in play occurs, the resource percentages  
                    lost are calculated as described in 3.1 to 3.4 and are accumulated to  
                    give updated values for the total resource percentage lost or resource 
                    available for the innings. This is done after each suspension as described  
                    in 5.2 and 5.5.
             **/
            //return resources lost
            return resourcesLeftAtSuspension - resourcesLeftAfterSuspension;
        }

        //this will replaced by serialization solution
        public List<List<double>> loadTable(string filename)
        {

            FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read);
            StreamReader sr = new StreamReader(file);
            string s = "";
            int ballsLeft = 0;
            string[] splitString;

            table = new List<List<double>>();

            while (!sr.EndOfStream)
            {

                s = sr.ReadLine();
                splitString = s.Split(' ');
                table.Add(new List<Double>());

                for (int i = 0; i < splitString.Length; i++)
                {
                    table[ballsLeft].Add(Double.Parse(splitString[i]));
                }
                ballsLeft++;
            }//end while(!sr.EndOfStream)
            //catch here?
            //finally here?        
            sr.Close();
            file.Close();

            return table;
        }


    }//class
}
